/*
 * Created by Jaren at 2021/12/13 13:58
 */
import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/base/base_factory.dart';
import 'package:inmotion_protocol/base/file/file_manager.dart';
import 'package:inmotion_protocol/base/protocol.dart';
import 'package:inmotion_protocol/base/vehicle_data.dart';
import 'package:inmotion_protocol/common/accessory_info.dart';
import 'package:inmotion_protocol/common/assistant_settings.dart';
import 'package:inmotion_protocol/common/bms_log_manager.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/common/fw_update_manager.dart';
import 'package:inmotion_protocol/common/log_file_manager.dart';
import 'package:inmotion_protocol/common/media_file_upload_manager.dart';
import 'package:inmotion_protocol/common/mode.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/common/response.dart';
import 'package:inmotion_protocol/common/riding_statistics_helper.dart';
import 'package:inmotion_protocol/common/vehicle_info.dart';
import 'package:inmotion_protocol/ezcan/bean/ebike/ebike_real_time_info.dart';
import 'package:inmotion_protocol/ezcan/bean/ebike/ebike_settings.dart';
import 'package:inmotion_protocol/ezcan/bean/ebike/ebike_statistics.dart';
import 'package:inmotion_protocol/ezcan/bean/euc/euc_settings.dart';
import 'package:inmotion_protocol/ezcan/bean/euc/euc_statistics.dart';
import 'package:inmotion_protocol/ezcan/bean/euc/real_time_data.dart';
import 'package:inmotion_protocol/ezcan/bean/real_time_info.dart';
import 'package:inmotion_protocol/ezcan/bean/scooter/scooter_real_time_info.dart';
import 'package:inmotion_protocol/ezcan/bean/scooter/scooter_settings.dart';
import 'package:inmotion_protocol/ezcan/bean/scooter/scooter_statistics.dart';
import 'package:inmotion_protocol/ezcan/bean/scv/scv_real_time_data.dart';
import 'package:inmotion_protocol/ezcan/bean/scv/scv_settings.dart';
import 'package:inmotion_protocol/ezcan/bean/scv/scv_statistics.dart';
import 'package:inmotion_protocol/ezcan/bean/settings.dart';
import 'package:inmotion_protocol/ezcan/bean/statistics.dart';
import 'package:inmotion_protocol/ezcan/ezcan_constant.dart';
import 'package:inmotion_protocol/ezcan/ezcan_file_download_manager.dart';
import 'package:inmotion_protocol/ezcan/ezcan_log_file_manager.dart';
import 'package:inmotion_protocol/ezcan/ezcan_message.dart';
import 'package:inmotion_protocol/ezcan/factory/ezcan_factory.dart';
import 'package:inmotion_protocol/ezcan/file/ezcan_file_manager.dart';
import 'package:inmotion_protocol/ezcan/file/response.dart';
import 'package:inmotion_protocol/ezcan/fw_update_manager.dart';
import 'package:inmotion_protocol/ezcan/lighteffect/light_effect_file_upload_manager.dart';
import 'package:inmotion_protocol/ezcan/sound/sound_pack_file_upload_manager.dart';
import 'package:inmotion_protocol/ezcan/util.dart';
import 'package:inmotion_protocol/lorin/bean/base/bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/base/tbox.dart';
import 'package:inmotion_protocol/lorin/bean/base/tire_pressure_sensor.dart';
import 'package:inmotion_protocol/lorin/bean/common/date.dart';
import 'package:inmotion_protocol/lorin/bean/common/response/response.dart';
import 'package:inmotion_protocol/lorin/bean/common/bms_info.dart';
import 'package:inmotion_protocol/lorin/constant.dart';
import 'package:inmotion_protocol/lorin/media/avatar_file_manager.dart';
import 'package:inmotion_protocol/lorin/protocol.dart';
import 'package:inmotion_protocol/protocol_worker.dart';
import 'package:inmotion_protocol/util/byte_util.dart';
import 'package:inmotion_protocol/util/date_time_util.dart';
import 'package:inmotion_protocol/util/log.dart';

class EzCANProtocol extends Protocol<EzcanMessage> {
  static const defaultBtPwd = "000000";

  /// 用于部分非通用接口的组合器实例
  /// 如请求设置数据时，根据车型可能需要组合多个请求
  MethodComposer? _composer;

  EzCANProtocol(ProtocolWorker<EzcanMessage> protocolWorker,
      MsgFactory<EzcanMessage> msgFactory)
      : super(protocolWorker, msgFactory);

  @override
  Future prepareOnLinkLayerConnected(String deviceName,
      {String clientId = '', bool resetData = true}) async {
    if (resetData) _statisticsMocker.reset();

    if (_needVerifyBtPwd(deviceName)) {
      return Future(() async {
        await Future.delayed(const Duration(milliseconds: 100), () {
          return verifyBtPwd().onError((error, stackTrace) {
            throw InitException(error.toString());
          });
        }).onError((e, stackTrace) {
          if (e is InitException) throw e;
          throw InitException(e.toString());
        });
      });
    }

    return await Future.delayed(const Duration(milliseconds: 200));
  }

  @override
  EzcanFactory msgFactory() {
    return super.msgFactory() as EzcanFactory;
  }

  @override
  int maxSizePeerPkg = 150;

  AbsRealTimeInfo? _cachedRealTimeInfo;
  int _cachedRealTimeInfoTimestamp = 0;
  final StatisticsMocker _statisticsMocker = StatisticsMocker();

  @override
  Future<AllRealTimeData> requestAllRealTimeData() {
    return composer().requestAllRealTimeInfo().then((allRealTimeInfo) {
      var realTimeInfo = allRealTimeInfo.realTimeInfo as AbsRealTimeInfo;
      _updateRealTimeInfoCache(realTimeInfo);

      return allRealTimeInfo;
    });
  }

  @override
  Future<VehicleSynthesizeRealTimeInfo> requestVehicleSynthesizeRealTimeInfo() {
    throw UnimplementedError();
  }

  @override
  Future<ProductProperty> requestProductProperty() {
    return protocolWorker()
        .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(),
            timeoutMs: 500, maxRetryTimes: 3)
        .then((rspMsg) {
      return EzcanUtil.parseInitInfoFromSlowMsg(rspMsg);
    }).catchError((error) {
      if (error is MsgTimeoutException)
        throw RequestProductPropertyFailedException.bySNTimeout();
      if (error is NotSupportException) throw error;
      throw RequestProductPropertyFailedException.bySNParseFailed();
    });
  }

  @override
  Future<ProductProperty> requestProductPropertyV2() {
    throw UnimplementedError(
        "requestProductPropertyV2 is not implemented in EzcanProtocol");
  }

  @override
  Future<RealTimeError> requestRealTimeError() {
    return (composer()).requestRealTimeError();
  }

  @override
  Future<RealTimeInfo> requestRealTimeInfo() {
    return (composer()).requestRealTimeInfo().then((realTimeInfo) {
      _updateRealTimeInfoCache(realTimeInfo);
      return realTimeInfo;
    });
  }

  @override
  Future<RealTimeState> requestRealTimeState() {
    return (composer()).requestRealTimeState();
  }

  @override
  Future<HistoryStatistics> requestCurrentStatistics() {
    if (_isRealTimeInfoCacheValid()) {
      EzCANHistoryStatistics statistics;
      if (productProperty.model.isV5Series()) {
        statistics = V5HistoryStatistics();
      } else if (productProperty.model.isV8()) {
        statistics = V8HistoryStatistics();
      } else if (productProperty.model.isV10Like()) {
        statistics = V10LikeHistoryStatistics();
      } else if (productProperty.model.isL8Series()) {
        statistics = L8HistoryStatistics();
      } else if (productProperty.model.isP1Series()) {
        statistics = EBikeHistoryStatistics();
      } else if (productProperty.model.isP2Series()) {
        statistics = EBikeHistoryStatistics();
      } else if (productProperty.model.isR1Series()) {
        statistics = R1HistoryStatistics();
      } else {
        throw NotSupportException("");
      }
      statistics.calculate(_cachedRealTimeInfo!, _statisticsMocker);
      return Future.value(statistics);
    }
    return requestAllRealTimeData()
        .then((allRealTimeData) => requestCurrentStatistics());
  }

  @override
  Future<StatisticsInfoResponse> requestHistoryStatisticsInfo() {
    throw UnimplementedError();
  }

  @override
  Future<StatisticsResponse> requestHistoryStatistics(int index, int count) {
    throw UnimplementedError();
  }

  @override
  Future<TotalStatistics> requestTotalStatistics() {
    if (_isRealTimeInfoCacheValid()) {
      EzCANTotalStatistics statistics;
      if (productProperty.model.isV5Series()) {
        statistics = V5TotalStatistics();
      } else if (productProperty.model.isV8()) {
        statistics = V8TotalStatistics();
      } else if (productProperty.model.isV10Like()) {
        statistics = V10LikeTotalStatistics();
      } else if (productProperty.model.isL8Series()) {
        statistics = L8TotalStatistics();
      } else if (productProperty.model.isP1Series()) {
        statistics = EBikeTotalStatistics();
      } else if (productProperty.model.isP2Series()) {
        statistics = EBikeTotalStatistics();
      } else if (productProperty.model.isR1Series()) {
        statistics = R1TotalStatistics();
      } else {
        throw NotSupportException("");
      }
      statistics.fromRealTimeInfo(_cachedRealTimeInfo!);
      return Future.value(statistics);
    }
    return requestAllRealTimeData()
        .then((allRealTimeData) => requestTotalStatistics());
  }

  bool _isRealTimeInfoCacheValid() {
    // 10s内不过期
    return _cachedRealTimeInfo != null &&
        (DateTimeUtil.current() - _cachedRealTimeInfoTimestamp <= 10 * 1000);
  }

  void _updateRealTimeInfoCache(AbsRealTimeInfo? realTimeInfo) {
    _cachedRealTimeInfo = realTimeInfo;
    _cachedRealTimeInfoTimestamp = DateTimeUtil.current();

    if (!productProperty.model.isV10Like()) {
      if (_statisticsMocker.rideTimeCountStartAt == -1 ||
          _statisticsMocker.totalMileageCountStartAt == -1) {
        _statisticsMocker.rideTimeCountStartAt =
            DateTimeUtil.current(second: true);
        _statisticsMocker.totalMileageCountStartAt =
            realTimeInfo!.totalMileage.value;
      } else {
        realTimeInfo!.mileage = ByteUtil.toUint16(
            realTimeInfo.totalMileage.value -
                _statisticsMocker.totalMileageCountStartAt);
        realTimeInfo.rideTime = ByteUtil.toUint32(
            DateTimeUtil.current(second: true) -
                _statisticsMocker.rideTimeCountStartAt);
      }
    }
  }

  @override
  Future<SettingsResponse> lostMode([bool enable = true]) {
    throw NotSupportException("Not support!");
  }

  @override
  Future<Settings> requestSettings() {
    return composer().requestSettings();
  }

  @override
  Future<void> respondQuickConnect() {
    return protocolWorker().send(EzcanFactory.genQuickConnectAckMsg());
  }

  Future<EzcanMessage> verifyBtPwd() {
    return protocolWorker().sendAndGetRsp(
        EzcanFactory.genVerifyPwdMsg(defaultBtPwd),
        maxRetryTimes: 3);
  }

  Future<bool> resetBtPwd() {
    return protocolWorker()
        .sendAndGetRsp(EzcanFactory.genResetPwdPwdMsg(defaultBtPwd),
            timeoutMs: 500)
        .then((rspMsg) => rspMsg.data[0] == 1);
  }

  @override
  Future<DeviceWrapper> requestDevicesId(List<int> devices) {
    return Future.value(DeviceWrapper());
  }

  @override
  Future<DateTime> requestActivatedTime() {
    throw UnsupportedError("Activated time is not supported!");
  }

  @override
  void setup(ProductModel model, VersionWrapper version) {
    productProperty.model = model;
    productProperty.versionWrapper = version;
    ProductProperty.setDefaultProperty(productProperty);
    if (model.isV5Series()) {
      _composer = _V5Composer(protocolWorker(), msgFactory(), productProperty);
    } else if (model.isV10Like()) {
      _composer =
          _V10LikeComposer(protocolWorker(), msgFactory(), productProperty);
    } else if (model.isV8Series()) {
      _composer = _V8Composer(protocolWorker(), msgFactory(), productProperty);
    } else if (model.isL8Series()) {
      _composer = _L8Composer(protocolWorker(), msgFactory(), productProperty);
    } else if (model.isP1Series()) {
      _composer = _P1Composer(protocolWorker(), msgFactory(), productProperty);
      protocolWorker().defaultTimeoutMs = 1000;
    } else if (model.isP2Series()) {
      _composer =
          _P2LikeComposer(protocolWorker(), msgFactory(), productProperty);
      protocolWorker().defaultTimeoutMs = 1000;
    } else if (model.isR1Series()) {
      _composer = _R1Composer(protocolWorker(), msgFactory(), productProperty);
      protocolWorker().defaultTimeoutMs = 1000;
    } else {
      throw NotSupportException('Model [$model] is not supported!');
    }
    msgFactory().init(productProperty);
  }

  /// 上次快速连接请求时间戳
  int lastRespondQuickConnectTimestamp = 0;

  @override
  void setUnhandledMsgHandler(Function f) {
    super.setUnhandledMsgHandler((msg) {
      if (EzcanUtil.isQuickConnectRequestMsg(msg)) {
        /// 快速连接请求
        int now = DateTime.now().millisecondsSinceEpoch;
        if (now - lastRespondQuickConnectTimestamp >= 100) {
          /// 100ms内仅响应1次
          respondQuickConnect();
          lastRespondQuickConnectTimestamp = now;
        }
        return true;
      }
      return f(msg);
    });
  }

  @override
  Future<List<EsimModel>> requestTBoxEsimList() {
    throw UnimplementedError();
  }

  @override
  Future<TBoxInfo> requestTBoxRealTimeInfo() {
    throw UnimplementedError();
  }

  @override
  Future<bool> rebootTBox(int mode) {
    throw UnimplementedError();
  }

  @override
  Future<TBoxInfo> requestTBoxInfo() {
    throw UnimplementedError();
  }

  @override
  Future<bool> activate(DateTime dateTime) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> autoHeadlightOnOff([bool on = true]) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> autoScreenOffOnOff([bool on = true]) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> startAccHandleCalibration() {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genCalibrateMsg(), timeoutMs: 1000)
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> startBalanceCalibration() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> startBrakeHandleCalibration() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> startTurningCalibration() {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genCalibrateMsg(), timeoutMs: 1000)
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> cruiseOnOff([bool on = true]) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genCruiseOnOffMsg(on), timeoutMs: 1000)
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> fanOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> fanQuietModeOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> hacOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> hdcOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> loadDetectOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> lock([bool lock = true]) {
    var lockRsp = protocolWorker()
        .sendAndGetRsp(msgFactory().genLockMsg(lock))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));

    if (productProperty.model.isL8Series()) {
      return lockRsp.then((rsp) {
        return protocolWorker()
            .sendAndGetRsp(msgFactory().genPatchL8LockBugMsg(lock))
            .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
      });
    }
    return lockRsp;
  }

  @override
  Future<SettingsResponse> lowBatLevelProtectionModeOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> noLoadDetectOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> overSpeedWarningOnOff([bool on = true]) {
    return protocolWorker()
        .sendAndGetRsp(EzcanFactory.genSetModeMsg(on
            ? EzcanConstant.MODE_OVER_SPEED_WARNING_ON
            : EzcanConstant.MODE_OVER_SPEED_WARNING_OFF))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> playSoundItem(int index) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genPlaySoundItemMsg(index + 1))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> horn() {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genPlaySoundItemMsg(24))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<AbsCalibrationResultResponse> queryHandleCalibrationResult(
      [int? which]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> remainderRangeEstimateOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> safeSpeedLimitOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setAutoHeadlightBrightnessThr(
      int lowThr, int highThr) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> autoLowHighBeamOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setHeadlightBrightness(
      {int? brightness, int? lowBeamBrightness, int? highBeamBrightness}) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setDeviceName(String name) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setDriveMode(int mode) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetDriveModeMsg(mode))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setPassword(String pwd, [int? type]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setPasswordType(int type) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setPedalSensitivity(int sensitivity,
      [int? sensitivity2]) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetPedalSensitivityMsg(sensitivity))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setPitchAngleZero(int angle) {
    angle = (angle * 655.35).toInt();
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetPitchAngleZeroMsg(angle))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setRidingMode(int mode, [var param]) {
    if (param == null || param is! AssistanceSettings)
      throw InvalidParamException(
          'Param [param] could not be null and should be an instance of AssistanceSettings.');
    AssistanceSettings copy = param.copy();
    copy.updateByRidingMode(mode);
    EzcanMessage msg = msgFactory().genSetAssistantSettingsMsg(copy);
    return protocolWorker()
        .sendAndGetRsp(msg)
        .then((rspMsg) => EzcanUtil.parseAssistanceSettingsRsp(msg, rspMsg));
  }

  @override
  Future<SettingsResponse> setAssistantMode(int mode, [var param]) {
    if (param == null || param is! AssistanceSettings)
      throw InvalidParamException(
          'Param [param] could not be null and should be an instance of AssistanceSettings.');
    AssistanceSettings copy = param.copy();
    copy.updateByAssistanceMode(mode);
    EzcanMessage msg = msgFactory().genSetAssistantSettingsMsg(copy);
    return protocolWorker()
        .sendAndGetRsp(msg)
        .then((rspMsg) => EzcanUtil.parseAssistanceSettingsRsp(msg, rspMsg));
  }

  @override
  Future<SettingsResponse> setSoundPackId(int id) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setSoundWaveSensitivity(int sensitivity) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setSpeedLimit(int speedLimit, [int? speedLimit2]) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetSpeedLimitMsg(speedLimit))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setSpeedLimitOfAssistMode(int speedLimit) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setAutoLowHighBeamSwitchSpeedThr(int speedThr) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setSpeedingBrakingSensitivity(
      int speeding, int braking) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> setStandbyTime(int seconds) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetStandbyTimeMsg(seconds))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setVolume(int volume) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetVolumeMsg(volume * 100))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> soundPackOnOff([bool on = true]) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSoundPackOnOffMsg(on))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> soundWaveOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> speedingBrakingOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> spinKillOnOff([bool on = true]) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSpinKillOnOffMsg(on))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> transportationModeOnOff([bool on = true]) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genTransportationModeOnOffMsg(on))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> usbPowerOnOff([bool on = true]) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> zeroSpeedupOnOff(
      [bool on = true, AbsAssistanceSettings? assistanceSettings]) {
    if (assistanceSettings == null || assistanceSettings is! AssistanceSettings)
      throw InvalidParamException(
          'Param [assistanceSettings] could not be null.');
    AssistanceSettings assistanceSettingsCopy = assistanceSettings.copy();
    assistanceSettingsCopy.updateByZeroSpeedStartUp(on);
    var sentMsg =
        msgFactory().genSetAssistantSettingsMsg(assistanceSettingsCopy);
    return protocolWorker().sendAndGetRsp(sentMsg).then(
        (rspMsg) => EzcanUtil.parseAssistanceSettingsRsp(sentMsg, rspMsg));
  }

  @override
  Future<Uint8ClampedList> requestLightEffectMode() {
    throw UnimplementedError();
  }

  @override
  Future<bool> syncRTC(DateTime? dateTime) {
    if (productProperty.model.isV10Like()) {
      dateTime = dateTime ?? DateTime.now();
      return protocolWorker()
          .sendAndGetRsp(EzcanFactory.genSyncRTCMsg(dateTime))
          .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg).isSuccess());
    }
    return Future.value(true);
  }

  @override
  Future<SettingsResponse> headlightOnOff(
      {bool? on, bool? lowBeamOn, bool? highBeamOn}) {
    if (productProperty.model.isL8Series()) {
      return protocolWorker()
          .sendAndGetRsp(
              EzcanFactory.genSetModeMsg((on ?? false) ? 0x0B : 0x0C))
          .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
    }
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genHeadlightOnOffMsg(on))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setLightEffectId(int id, [int? color]) {
    if (color != null) {
      /// L8设置指定氛围灯样式[id]的颜色
      return protocolWorker()
          .sendAndGetRsp(msgFactory().genSetLightEffectColorMsg(id, color))
          .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
    }
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetLightEffectIdMsg(id), timeoutMs: 800)
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setLightEffectMode(
      {bool? onOff, int? mode, int? paramColor, int? paramMode}) {
    if (onOff == null)
      throw InvalidParamException(
          'Param [onOff] could not be null on Ezcan product model.');
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genLightEffectOnOffMsg(onOff))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<bool> buildSecurityConnection() {
    return Future.value(true);
  }

  @override
  FwUpdateManager createFwUpdateManager(LinkLayerDeviceHandler handler,
      RequiredManualOperationHandler requiredManualOperationHandler) {
    return EzCANFwUpdateManager(this, handler, requiredManualOperationHandler);
  }

  _EzcanComposer composer() {
    if (_composer == null) throw Exception('You should call [setup] first!');
    return _composer! as _EzcanComposer;
  }

  @override
  Future<OpenFileResponse> openFile(
      {int? target, int? openType, String? name, int? type, int? tag}) {
    if (type == null || tag == null)
      throw InvalidParamException('Param [tag] and [type] could not be null.');
    return protocolWorker()
        .sendAndGetRsp(EzcanFactory.genOpenFileMsg(type, tag), timeoutMs: 800)
        .then((rspMsg) {
      int existsFileSize = ByteUtil.bytes2IntLe(rspMsg.data, 0, 4);
      if (existsFileSize >= 0) return OpenFileResponse.success(existsFileSize);
      return OpenFileResponse.byOriginError(existsFileSize);
    });
  }

  @override
  Future<EzCANFileResponse> setFileOffset({int? type, int? offset}) {
    if (type == null || offset == null)
      throw InvalidParamException(
          'Param [type] and [offset] could not be null.');
    return protocolWorker()
        .sendAndGetRsp(EzcanFactory.genSetFileOffsetMsg(type, offset),
            timeoutMs: 800, maxRetryTimes: 3)
        .then((rspMsg) => EzcanUtil.parseFileRsp(rspMsg));
  }

  @override
  Future<EzCANFileResponse> writeFile(Uint8ClampedList content,
      {int? tab,
      int? target,
      int? fileHandle,
      int? offset,
      int? contentLength}) {
    return protocolWorker()
        .sendAndGetRsp(EzcanFactory.genWriteFileMsg(content),
            timeoutMs: 1000, maxRetryTimes: 3)
        .then((rspMsg) => EzcanUtil.parseFileRsp(rspMsg));
  }

  @override
  Future<EzCANFileResponse> closeFile({int? target, int? fileHandle}) {
    return protocolWorker()
        .sendAndGetRsp(EzcanFactory.genCloseFileMsg(),
            timeoutMs: 800, maxRetryTimes: 3)
        .then((rspMsg) => EzcanUtil.parseFileRsp(rspMsg));
  }

  @override
  Future<FileResponse> checkFile(
      {int? target,
      int? fileHandle,
      int? offset,
      int? length,
      Uint8ClampedList? check}) {
    throw UnimplementedError();
  }

  @override
  Future<VersionWrapper> requestFwVersion([int? target]) {
    return requestProductProperty().then((productProperty) {
      return productProperty.versionWrapper;
    });
  }

  @override
  Future<SettingsResponse> startUpdate(int target, {Uint8ClampedList? para}) {
    throw UnimplementedError();
  }

  @override
  SoundFileUploadManager createSoundFileUploadManager() {
    return EzcanSoundFileUploadManager(this);
  }

  @override
  IFileManager createFileUploadManager(FileConfig config) {
    return EzCANFileManager(this, config as EzcanConfig);
  }

  @override
  LightEffectPkgFileUploadManager createLightEffectPkgUploadManager() {
    return EzcanLightEffectFileUploadManager(this);
  }

  @override
  Future<FileResponse> deleteFile(String path, {int? target}) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<List<int>> getSoundPackIdList({int? currentSoundPackId}) {
    if (currentSoundPackId == null) return Future.value([]);
    return Future.value([currentSoundPackId]);
  }

  @override
  Future<FileListResponse> getFileList({Object? filter}) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<int> getRemainStorageCapacity({int diskIndex = 0}) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<FileResponse> renameFile(String filePath, String newFilePath) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<List<int>> getSoundItemIndexList() {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<List<int>> getLightEffectPkgIdList() {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genRequestLightEffectIdListMsg())
        .then((rspMsg) {
      Uint8ClampedList? data = rspMsg.extra;
      List<int> idList = [];
      if (data == null) return idList;

      for (int i = 0; i < data.length; i = i + 4) {
        int id = ByteUtil.bytes2UIntLe(data, i, 4);
        if (id > 0) idList.add(id);
      }
      return idList;
    });
  }

  @override
  Future<SettingsResponse> setSpeedUnit(int unit) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> requestDeviceName() {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<SettingsResponse> factoryReset({int level = 1}) {
    if (!productProperty.model.isEzcanEuc())
      throw UnsupportedError(
          "Current model [${productProperty.model.toString()}] doesn't");

    return composer()
        .checkWorkMode(Mode.working, reserve: true)
        .then((notWorking) {
      if (!notWorking) return SettingsResponse.notNow();

      if (productProperty.model.isV5Series()) {
        return protocolWorker()
            .sendAndGetRsp(msgFactory().genEraseDataMsg(), timeoutMs: 45000)
            .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
      }

      /// V8和V10
      return protocolWorker()
          .sendAndGetRsp(msgFactory().genLightEffectOnOffMsg(false))
          .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg))
          .then((value) {
        if (value.isSuccess()) {
          return Future.delayed(const Duration(seconds: 2), () {
            return protocolWorker()
                .sendAndGetRsp(msgFactory().genEraseDataMsg(), timeoutMs: 45000)
                .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
          });
        }
        return value;
      });
    });
  }

  @override
  AvatarFileManager createAvatarFileManager() {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  IFileManager createFileDownloadManager(FileConfig config) {
    return EzCANFileDownloadManager(this);
  }

  @override
  Future<FileResponse> deleteDiySoundItem(int soundIndex) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<FileResponse> deleteSoundPack(int id) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<FileResponse> deleteLightEffectPkg(int id) {
    throw UnsupportedError("Don't support this method.");
  }

  @override
  Future<FileResponse> getFile(
      {int? tab,
      int? target,
      int? fileHandle,
      int? offset,
      int? contentLength}) {
    throw UnimplementedError();
  }

  @override
  Future<FileResponse> getFileCheck(
      {int? target, int? fileHandle, int? offset}) {
    throw UnimplementedError();
  }

  @override
  LogFileManager createLogFileManager() {
    return EzCANLogFileManager(this);
  }

  /// 根据设备名称判断是否支持快速连接
  static bool _needRespondQuickConnectRsp(String deviceName) {
    return RegExp(r"^V8F|V8S|V10").hasMatch(deviceName);
  }

  /// 根据设备名称判断是否需要验证蓝牙密码
  static bool _needVerifyBtPwd(String deviceName) {
    return RegExp(r"^R1|L8|V5|V8").hasMatch(deviceName);
  }

  @override
  Future<SettingsResponse> setMaxChargeLevel(int level) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> setMaxDcOutputLevel(int level) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> setUSBMode(int mode) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<AbsBMSCellsVoltage> requestBMSCellsVoltage(int target) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<Datetime> requestBMSDate(int which) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<BMSFixedInfo> requestBMSFixedInfo(int which) {
    throw UnsupportedError("Not support this operation.");
  }

  Future<BMSLog> requestBMSLog(int which, int index) {
    throw UnsupportedError("Not support this operation.");
  }

  Future<int> requestBMSLogCount(int which) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<BMSAllRealTimeInfo> requestBMSRealTimeInfo(int which) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> assistBalanceOnOff([bool on = true]) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<AbsCalibrationResultResponse> queryMotorAutoCalibrationResult() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> startMotorAutoCalibration(
      {int hallOffsetCorrect = 1, int hallSectorCorrect = 1}) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> resetMotorAutoCalibrationEffect(
      {int hallOffset = 1, int hallSector = 1}) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<AbsCalibrationResultResponse> queryMotorSelfCheckResult() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> startBatteryCalibration() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> startMotorSelfCheck({int method = 1}) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> stopMotorAutoCalibration() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> stopMotorSelfCheck() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<AbsCalibrationResultResponse> queryBatteryCalibrationResult() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<AbsCalibrationResultResponse> queryIMUCalibrationResult() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<AbsCalibrationResultResponse> queryCalibrationResult(int which) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> startCalibration(int which) {
    if (which == Constant.calibrationTurning) return startTurningCalibration();
    if (which == Constant.calibrationAccHandle)
      return startAccHandleCalibration();
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> disableChargeDangerAlert() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> setWarningLimitSpeed(int speed1, int speed2) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<bool> bindTirePressureSensor(
      String sensorId) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> tirePressureWarningOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setLowTirePressureWarningThreshold(int threshold) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setLogoLightBrightness(int brightness) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setTurnSignalMode(int mode) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setBermAngle(int angle) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setOutputThreshold(int tiltBack, int warning1, int warning2) {
    throw UnimplementedError();
  }

  @override
  Future<List<TirePressureSensor>> searchTirePressureSensor() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> resetTirePressureSensorSearchResult() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  RidingStatisticsHelper createRidingStatisticsHelper() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<AccessoryWrapper> requestAccessoriesInfo() {
    return Future.value(AccessoryWrapper());
  }

  @override
  Future<BatteryRealTimeInfo> requestBatteryRealTimeInfo() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<FirmwareState> requestFirmwareState() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> writeForceUpdate(
      int level, String minVersion, String maxVersion) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> bermAngleModeOnOff([bool on = true]) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  AbsBmsLogManager createBMSLogManager() {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> brakeFirstModeOnOff([bool on = true]) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> onePedalModeOnOff([bool on = true]) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> setAccForce(int force, {int? type}) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> setBrakeForce(int force, {int? type}) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> setParkTime(int seconds) {
    throw UnsupportedError("Not support this operation.");
  }

  @override
  Future<SettingsResponse> gpsOnOff([bool on = true]) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genGpsOnOffMsg(on))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setLanguage(int language) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetLanguageMsg(language))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> setTurningSensitivity(int sensitivity) {
    return protocolWorker()
        .sendAndGetRsp(msgFactory().genSetTurningSensitivity(sensitivity))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<SettingsResponse> powerOnOff([bool on = true]) {
    // 0x01 - 新手模式开机
    // 0x02 - 普通模式开机
    // 0x05 - 关机
    return protocolWorker()
        .sendAndGetRsp(EzcanFactory.genSetModeMsg(on ? 0x02 : 0x05))
        .then((rspMsg) => EzcanUtil.parseSettingsRsp(rspMsg));
  }

  @override
  Future<void> requestRebootHmic() {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> twoBatteryMode([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> daytimeRunningLightOnOff([bool on = true]) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> startTransfer(int target, {Uint8ClampedList? para}) {
    throw UnimplementedError();
  }
  
  @override
  Future<SettingsResponse> showTboxInfoOnVehicleOnOff([bool on = true]) {
    throw UnimplementedError();
  }
  
  @override
  Future<SettingsResponse> tboxLowBatLevelWakeUpVehicleModeOnOff([bool on = true]) {
    throw UnimplementedError();
  }


  @override
  Future<SettingsResponse> setMaxChargeCurrent(int currentAc220, int currentAc110) {
    throw UnimplementedError();
  }

  @override
  Future<SettingsResponse> setChargeLimitPercentage(int percentage) {
    throw UnimplementedError();
  }
}

abstract class _EzcanComposer
    extends MethodComposer<EzcanMessage, EzcanFactory> {
  _EzcanComposer(ProtocolWorker<EzcanMessage> protocolWorker,
      MsgFactory msgFactory, ProductProperty property)
      : super(protocolWorker, msgFactory, property);

  EzcanFactory _msgFactory() {
    return msgFactory as EzcanFactory;
  }

  Future<AbsRealTimeInfo> requestRealTimeInfo();

  Future<AbsRealTimeState> requestRealTimeState();

  Future<AbsRealTimeError> requestRealTimeError();

  Future<bool> checkWorkMode(Mode targetMode, {bool reserve = false});
}

class _V5Composer extends _EzcanComposer {
  _V5Composer(ProtocolWorker<EzcanMessage> protocolWorker,
      EzcanFactory msgFactory, ProductProperty property)
      : super(protocolWorker, msgFactory, property);

  @override
  Future<V5AllRealTimeInfo> requestAllRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V5RealTimeInfo realTimeInfo =
          V5RealTimeInfo.fromBytes(property, rspMsg.extra!, 0);
      V5RealTimeState realTimeState =
          V5RealTimeState.fromBytes(rspMsg.extra!, 0);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((rspMsg) {
        if (rspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(rspMsg.extra!, 80));

        return protocolWorker
            .sendAndGetRsp(EzcanFactory.genRequestErrorCodeMsg(),
                timeoutMs: 500)
            .then((rspMsg) {
          V5RealTimeError error = V5RealTimeError.fromBytes(rspMsg.data);
          return V5AllRealTimeInfo(realTimeInfo, realTimeState, error);
        });
      });
    });
  }

  @override
  Future<V5Settings> requestSettings() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(),
            timeoutMs: 500, maxRetryTimes: 2)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException("extra must bt not null.");
      V5Settings settings = V5Settings.fromBytes(rspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(_msgFactory().genRequestVolumeMsg(),
              timeoutMs: 500, maxRetryTimes: 2)
          .then((rspMsg) {
        settings.volume =
            ByteUtil.toUint8(ByteUtil.bytes2UIntLe(rspMsg.data, 0, 4) ~/ 100);

        return protocolWorker
            .sendAndGetRsp(_msgFactory().genRequestSpinKillStateMsg(),
                timeoutMs: 500, maxRetryTimes: 2)
            .then((rspMsg) {
          settings.spinKillState =
              ByteUtil.toUint4(ByteUtil.bytes2UIntLe(rspMsg.data, 0, 4));
          return protocolWorker
              .sendAndGetRsp(EzcanFactory.genRequestSoundPackIdMsg(),
                  timeoutMs: 500, maxRetryTimes: 2)
              .then((rspMsg) {
            settings.soundPackId = ByteUtil.bytes2Uint32Le(rspMsg.data);
            return settings;
          });
        });
      });
    });
  }

  @override
  Future<AbsRealTimeError> requestRealTimeError() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestErrorCodeMsg(), timeoutMs: 500)
        .then((rspMsg) {
      return V5RealTimeError.fromBytes(rspMsg.data);
    });
  }

  @override
  Future<AbsRealTimeInfo> requestRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return V5RealTimeInfo.fromBytes(property, rspMsg.extra!, 0);
    });
  }

  @override
  Future<AbsRealTimeState> requestRealTimeState() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V5RealTimeState realTimeState =
          V5RealTimeState.fromBytes(rspMsg.extra!, 0);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((rspMsg) {
        if (rspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(rspMsg.extra!, 80));
        return realTimeState;
      });
    });
  }

  @override
  Future<bool> checkWorkMode(Mode targetMode, {bool reserve = false}) {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V5RealTimeState realTimeState =
          V5RealTimeState.fromBytes(rspMsg.extra!, 0);

      if (reserve) return realTimeState.pcMode != targetMode;
      return realTimeState.pcMode == targetMode;
    });
  }
}

class _V8Composer extends _EzcanComposer {
  _V8Composer(ProtocolWorker<EzcanMessage> protocolWorker,
      EzcanFactory msgFactory, ProductProperty property)
      : super(protocolWorker, msgFactory, property);

  @override
  Future<AbsAllRealTimeInfo> requestAllRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V8RealTimeInfo realTimeInfo =
          V8RealTimeInfo.fromBytes(property, fastInfoRspMsg.extra!, 0);
      V8RealTimeState realTimeState =
          V8RealTimeState.fromBytes(fastInfoRspMsg.extra!, 0);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((slowInfoRspMsg) {
        if (slowInfoRspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(slowInfoRspMsg.extra!, 80));

        if (property.model.isV8()) {
          // V8需要继续获取错误码
          return protocolWorker
              .sendAndGetRsp(EzcanFactory.genRequestErrorCodeMsg(),
                  timeoutMs: 500)
              .then((errorCodeRspMsg) {
            V8RealTimeError error =
                V8RealTimeError.fromBytes(errorCodeRspMsg.data);
            return V8AllRealTimeInfo(realTimeInfo, realTimeState, error);
          });
        } else {
          // V8S和V8F等可直接从快速数据中解析实时错误码
          V8RealTimeError error =
              V8RealTimeError.fromBytes(fastInfoRspMsg.extra!);
          return V8AllRealTimeInfo(realTimeInfo, realTimeState, error);
        }
      });
    });
  }

  @override
  Future<V8Settings> requestSettings() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(),
            timeoutMs: 500, maxRetryTimes: 2)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException("extra must bt not null.");
      V8Settings settings = V8Settings.fromBytes(rspMsg.extra!);
      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestLightEffectIdMsg(),
              timeoutMs: 500, maxRetryTimes: 2)
          .then((rspMsg) {
        settings.lightEffectId = ByteUtil.bytes2Uint32Le(rspMsg.data, 4);
        return protocolWorker
            .sendAndGetRsp(EzcanFactory.genRequestSoundPackIdMsg(),
                timeoutMs: 500, maxRetryTimes: 2)
            .then((rspMsg) {
          settings.soundPackId = ByteUtil.bytes2Uint32Le(rspMsg.data);
          return settings;
        });
      });
    });
  }

  @override
  Future<AbsRealTimeError> requestRealTimeError() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestErrorCodeMsg(), timeoutMs: 500)
        .then((errorCodeRspMsg) {
      return V8RealTimeError.fromBytes(errorCodeRspMsg.data);
    });
  }

  @override
  Future<AbsRealTimeInfo> requestRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return V8RealTimeInfo.fromBytes(property, fastInfoRspMsg.extra!, 0);
    });
  }

  @override
  Future<AbsRealTimeState> requestRealTimeState() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V8RealTimeState realTimeState =
          V8RealTimeState.fromBytes(fastInfoRspMsg.extra!, 0);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((slowInfoRspMsg) {
        if (slowInfoRspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(slowInfoRspMsg.extra!, 80));

        return realTimeState;
      });
    });
  }

  @override
  Future<bool> checkWorkMode(Mode targetMode, {bool reserve = false}) {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V8RealTimeState realTimeState =
          V8RealTimeState.fromBytes(rspMsg.extra!, 0);

      if (reserve) return realTimeState.pcMode != targetMode;
      return realTimeState.pcMode == targetMode;
    });
  }
}

class _V10LikeComposer extends _EzcanComposer {
  _V10LikeComposer(ProtocolWorker<EzcanMessage> protocolWorker,
      EzcanFactory msgFactory, ProductProperty property)
      : super(protocolWorker, msgFactory, property);

  @override
  Future<AbsAllRealTimeInfo> requestAllRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V10LikeRealTimeInfo realTimeInfo =
          V10LikeRealTimeInfo.fromBytes(property, fastInfoRspMsg.extra!, 0);
      V10LikeRealTimeState realTimeState =
          V10LikeRealTimeState.fromBytes(fastInfoRspMsg.extra!, 0);
      V10LikeRealTimeError error =
          V10LikeRealTimeError.fromBytes(fastInfoRspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((slowInfoRspMsg) {
        if (slowInfoRspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(slowInfoRspMsg.extra!, 80));
        realTimeInfo.updateBySlowInfoBytes(slowInfoRspMsg.extra!);
        return V10LikeAllRealTimeInfo(realTimeInfo, realTimeState, error);
      });
    });
  }

  @override
  Future<V10Settings> requestSettings() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(),
            timeoutMs: 500, maxRetryTimes: 2)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException("extra must bt not null.");
      V10Settings settings = V10Settings.fromBytes(rspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(),
              timeoutMs: 500, maxRetryTimes: 2)
          .then((rspMsg) {
        if (rspMsg.extra == null)
          throw ProtocolParseException("extra must bt not null.");
        V10LikeRealTimeState realTimeState =
            V10LikeRealTimeState.fromBytes(rspMsg.extra!, 0);
        settings.lockState = realTimeState.lockState;
        settings.transportationModeState =
            realTimeState.transportationModeState;
        realTimeState.pcMode;
        return protocolWorker
            .sendAndGetRsp(EzcanFactory.genRequestSoundPackIdMsg(),
                timeoutMs: 500, maxRetryTimes: 2)
            .then((rspMsg) {
          settings.soundPackId = ByteUtil.bytes2Uint32Le(rspMsg.data);
          return protocolWorker
              .sendAndGetRsp(EzcanFactory.genRequestLightEffectIdMsg(),
                  timeoutMs: 500, maxRetryTimes: 2)
              .then((rspMsg) {
            settings.lightEffectId = ByteUtil.bytes2Uint32Le(rspMsg.data);
            return settings;
          }).catchError((e) => settings);
        }).catchError((e) => settings);
      }).catchError((e) => settings);
    });
  }

  @override
  Future<AbsRealTimeError> requestRealTimeError() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return V10LikeRealTimeError.fromBytes(fastInfoRspMsg.extra!);
    });
  }

  @override
  Future<AbsRealTimeInfo> requestRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V10LikeRealTimeInfo realTimeInfo =
          V10LikeRealTimeInfo.fromBytes(property, fastInfoRspMsg.extra!, 0);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((slowInfoRspMsg) {
        if (slowInfoRspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeInfo.updateBySlowInfoBytes(slowInfoRspMsg.extra!);
        return realTimeInfo;
      });
    });
  }

  @override
  Future<AbsRealTimeState> requestRealTimeState() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V10LikeRealTimeState realTimeState =
          V10LikeRealTimeState.fromBytes(fastInfoRspMsg.extra!, 0);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((slowInfoRspMsg) {
        if (slowInfoRspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(slowInfoRspMsg.extra!, 80));
        return realTimeState;
      });
    });
  }

  @override
  Future<bool> checkWorkMode(Mode targetMode, {bool reserve = false}) {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      V10LikeRealTimeState realTimeState =
          V10LikeRealTimeState.fromBytes(rspMsg.extra!, 0);

      if (reserve) return realTimeState.pcMode != targetMode;
      return realTimeState.pcMode == targetMode;
    });
  }
}

class _L8Composer extends _EzcanComposer {
  _L8Composer(ProtocolWorker<EzcanMessage> protocolWorker,
      EzcanFactory msgFactory, ProductProperty property)
      : super(protocolWorker, msgFactory, property);

  @override
  Future<AbsAllRealTimeInfo> requestAllRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      L8RealTimeInfo realTimeInfo =
          L8RealTimeInfo.fromFastMsgRsp(property, rspMsg.extra!);
      L8RealTimeState realTimeState =
          L8RealTimeState.fromFastMsgRsp(rspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((rspMsg) {
        if (rspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(rspMsg.extra!, 80));

        realTimeInfo.batteryLevel =
            Uint16(_calBatteryLevel(rspMsg.extra!, realTimeInfo.voltage.value));

        return protocolWorker
            .sendAndGetRsp(EzcanFactory.genRequestErrorCodeMsg(),
                timeoutMs: 500)
            .then((rspMsg) {
          L8RealTimeError error =
              L8RealTimeError.fromErrorCodeMsgRsp(rspMsg.data);
          return L8AllRealTimeInfo(realTimeInfo, realTimeState, error);
        });
      });
    }).catchError((error) {
      LogUtils.e(error);
      throw (error);
    });
  }

  /// 计算电量
  int _calBatteryLevel(Uint8ClampedList slowMsgRspExtraData, int voltage) {
    int batteryLevel = 0;
    try {
      int limit1 = ByteUtil.bytes2Uint16Le(slowMsgRspExtraData, 108).value;
      int limit2 = ByteUtil.bytes2Uint16Le(slowMsgRspExtraData, 110).value;
      int limit3 = ByteUtil.bytes2Uint16Le(slowMsgRspExtraData, 112).value;
      int limit4 = ByteUtil.bytes2Uint16Le(slowMsgRspExtraData, 114).value;
      int limit5 = ByteUtil.bytes2Uint16Le(slowMsgRspExtraData, 116).value;
      int limit6 = ByteUtil.bytes2Uint16Le(slowMsgRspExtraData, 118).value;

      voltage = voltage * 10;

      if (voltage > limit1) {
        batteryLevel = 1;
      } else if (voltage > limit2) {
        batteryLevel =
            ((((voltage - limit2) / (limit1 - limit2)) * 0.2 + 0.8) * 10000)
                .toInt();
      } else if (voltage > limit3) {
        batteryLevel =
            ((((voltage - limit3) / (limit2 - limit3)) * 0.2 + 0.6) * 10000)
                .toInt();
      } else if (voltage > limit4) {
        batteryLevel =
            ((((voltage - limit4) / (limit3 - limit4)) * 0.2 + 0.4) * 10000)
                .toInt();
      } else if (voltage > limit5) {
        batteryLevel =
            ((((voltage - limit5) / (limit4 - limit5)) * 0.2 + 0.2) * 10000)
                .toInt();
      } else if (voltage > limit6) {
        batteryLevel =
            ((((voltage - limit6) / (limit5 - limit6)) * 0.2) * 10000).toInt();
      } else {
        batteryLevel = 0;
      }
    } catch (e) {
      LogUtils.e(e);
    }
    return batteryLevel;
  }

  @override
  Future<AbsSettings> requestSettings() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(),
            timeoutMs: 500, maxRetryTimes: 2)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException("extra must bt not null.");
      L8Settings settings = L8Settings.fromBytes(rspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(),
              timeoutMs: 500, maxRetryTimes: 2)
          .then((rspMsg) {
        if (rspMsg.extra == null)
          throw ProtocolParseException("extra must bt not null.");
        L8RealTimeState realTimeState =
            L8RealTimeState.fromFastMsgRsp(rspMsg.extra!);
        settings.lockState = realTimeState.lockState;

        return protocolWorker
            // 获取氛围灯开关
            .sendAndGetRsp(EzcanFactory.genRequestLightEffectIdMsg(),
                timeoutMs: 500, maxRetryTimes: 2)
            .then((rspMsg) {
          settings.lightEffectId = ByteUtil.bytes2Uint4Le(rspMsg.data);
          // 获取前氛围灯颜色
          return protocolWorker
              .sendAndGetRsp(
                  _msgFactory().genRequestLightEffectColorMsg(
                      settings.lightEffectId.value),
                  timeoutMs: 500,
                  maxRetryTimes: 2)
              .then((rspMsg) {
            if (rspMsg.extra == null)
              throw ProtocolParseException("extra must bt not null.");
            settings.frontLightEffectColor = ByteUtil.toUint32(
                L8Settings.parseLightEffectColor(rspMsg.extra!));
            // 获取后氛围灯颜色
            return protocolWorker
                .sendAndGetRsp(
                    _msgFactory().genRequestLightEffectColorMsg(
                        L8Settings.lightEffectTailLightFlag),
                    timeoutMs: 500,
                    maxRetryTimes: 2)
                .then((rspMsg) {
              if (rspMsg.extra == null)
                throw ProtocolParseException("extra must bt not null.");
              settings.tailLightEffectColor = ByteUtil.toUint32(
                  L8Settings.parseLightEffectColor(rspMsg.extra!));
              return settings;
            });
          });
        });
      });
    });
  }

  @override
  Future<AbsRealTimeError> requestRealTimeError() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestErrorCodeMsg(), timeoutMs: 500)
        .then((rspMsg) {
      return L8RealTimeError.fromErrorCodeMsgRsp(rspMsg.data);
    }).catchError((error) {
      LogUtils.e(error);
      throw (error);
    });
  }

  @override
  Future<AbsRealTimeInfo> requestRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return L8RealTimeInfo.fromFastMsgRsp(property, rspMsg.extra!);
    }).catchError((error) {
      LogUtils.e(error);
      throw (error);
    });
  }

  @override
  Future<AbsRealTimeState> requestRealTimeState() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      L8RealTimeState realTimeState =
          L8RealTimeState.fromFastMsgRsp(rspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 500)
          .then((rspMsg) {
        if (rspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(rspMsg.extra!, 80));

        return realTimeState;
      });
    }).catchError((error) {
      LogUtils.e(error);
      throw (error);
    });
  }

  @override
  Future<bool> checkWorkMode(Mode targetMode, {bool reserve = false}) {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      L8RealTimeState realTimeState =
          L8RealTimeState.fromFastMsgRsp(rspMsg.extra!);

      if (reserve) return realTimeState.pcMode != targetMode;
      return realTimeState.pcMode == targetMode;
    });
  }
}

class _P1Composer extends _EzcanComposer {
  _P1Composer(ProtocolWorker<EzcanMessage> protocolWorker,
      EzcanFactory msgFactory, ProductProperty property)
      : super(protocolWorker, msgFactory, property);

  @override
  Future<AbsAllRealTimeInfo> requestAllRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      P1RealTimeInfo realTimeInfo =
          P1RealTimeInfo.fromFastMsgRsp(property, fastInfoRspMsg.extra!);
      P1RealTimeState realTimeState =
          P1RealTimeState.fromFastMsgRsp(fastInfoRspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 1000)
          .then((slowInfoRspMsg) {
        if (slowInfoRspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        P1RealTimeError error =
            P1RealTimeError.fromErrorCodeMsgRsp(fastInfoRspMsg.extra!);
        return EBikeAllRealTimeInfo(realTimeInfo, realTimeState, error);
      });
    });
  }

  @override
  Future<P1Settings> requestSettings() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(),
            timeoutMs: 1000, maxRetryTimes: 2)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException("extra must bt not null.");
      P1Settings settings = P1Settings.fromSlowRspBytes(rspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(),
              timeoutMs: 1000, maxRetryTimes: 2)
          .then((rspMsg) {
        if (rspMsg.extra == null)
          throw ProtocolParseException("extra must bt not null.");
        P1RealTimeState realTimeState =
            P1RealTimeState.fromFastMsgRsp(rspMsg.extra!);
        settings.lockState = realTimeState.lockState;
        return settings;
      });
    });
  }

  @override
  Future<AbsRealTimeError> requestRealTimeError() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return P1RealTimeError.fromErrorCodeMsgRsp(fastInfoRspMsg.extra!);
    });
  }

  @override
  Future<AbsRealTimeInfo> requestRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return P1RealTimeInfo.fromFastMsgRsp(property, fastInfoRspMsg.extra!);
    });
  }

  @override
  Future<AbsRealTimeState> requestRealTimeState() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return P1RealTimeState.fromFastMsgRsp(fastInfoRspMsg.extra!);
    });
  }

  @override
  Future<bool> checkWorkMode(Mode targetMode, {bool reserve = false}) {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      P1RealTimeState realTimeState =
          P1RealTimeState.fromFastMsgRsp(rspMsg.extra!);

      if (reserve) return realTimeState.pcMode != targetMode;
      return realTimeState.pcMode == targetMode;
    });
  }
}

class _P2LikeComposer extends _EzcanComposer {
  _P2LikeComposer(ProtocolWorker<EzcanMessage> protocolWorker,
      EzcanFactory msgFactory, ProductProperty property)
      : super(protocolWorker, msgFactory, property);

  @override
  Future<AbsAllRealTimeInfo> requestAllRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      P2LikeRealTimeInfo realTimeInfo =
          P2LikeRealTimeInfo.fromFastMsgRsp(property, fastInfoRspMsg.extra!);
      P2LikeRealTimeState realTimeState =
          P2LikeRealTimeState.fromFastMsgRsp(fastInfoRspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 1000)
          .then((slowInfoRspMsg) {
        if (slowInfoRspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(slowInfoRspMsg.extra!, 80));
        P2LikeRealTimeError error =
            P2LikeRealTimeError.fromErrorCodeMsgRsp(fastInfoRspMsg.extra!);
        return P2LikeAllRealTimeInfo(realTimeInfo, realTimeState, error);
      });
    });
  }

  @override
  Future<P2LikeSettings> requestSettings() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(),
            timeoutMs: 1000, maxRetryTimes: 2)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException("extra must bt not null.");
      P2LikeSettings settings = P2LikeSettings.fromSlowRspBytes(rspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(),
              timeoutMs: 1000, maxRetryTimes: 2)
          .then((rspMsg) {
        if (rspMsg.extra == null)
          throw ProtocolParseException("extra must bt not null.");
        P2LikeRealTimeState realTimeState =
            P2LikeRealTimeState.fromFastMsgRsp(rspMsg.extra!);
        settings.lockState = realTimeState.lockState;

        return protocolWorker
            .sendAndGetRsp(_msgFactory().genRequestAssistantSettingsMsg(),
                timeoutMs: 1000, maxRetryTimes: 2)
            .then((rspMsg) {
          AssistanceSettings assistanceSettings =
              AssistanceSettings.fromBytes(property, rspMsg.data);
          settings.lockState = realTimeState.lockState;
          settings.assistanceSettings = assistanceSettings;
          settings.ridingMode = assistanceSettings.ridingMode;
          settings.assistantMode =
              ByteUtil.toUint8(assistanceSettings.getAssistantMode());
          settings.zeroStartupState =
              ByteUtil.bool2Uint4(assistanceSettings.isZeroStartOn());
          return settings;
        });
      });
    });
  }

  @override
  Future<R1RealTimeError> requestRealTimeError() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestErrorCodeMsg(), timeoutMs: 1000)
        .then((errorCodeRspMsg) {
      return R1RealTimeError.fromErrorCodeMsgRsp(errorCodeRspMsg.data);
    });
  }

  @override
  Future<AbsRealTimeInfo> requestRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return P2LikeRealTimeInfo.fromFastMsgRsp(property, fastInfoRspMsg.extra!);
    });
  }

  @override
  Future<AbsRealTimeState> requestRealTimeState() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return P2LikeRealTimeState.fromFastMsgRsp(fastInfoRspMsg.extra!);
    });
  }

  @override
  Future<bool> checkWorkMode(Mode targetMode, {bool reserve = false}) {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      P2LikeRealTimeState realTimeState =
          P2LikeRealTimeState.fromFastMsgRsp(rspMsg.extra!);

      if (reserve) return realTimeState.pcMode != targetMode;
      return realTimeState.pcMode == targetMode;
    });
  }
}

class _R1Composer extends _EzcanComposer {
  _R1Composer(super.protocolWorker, super.msgFactory, super.property);

  @override
  Future<bool> checkWorkMode(Mode targetMode, {bool reserve = false}) {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 500)
        .then((rspMsg) {
      if (rspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      R1RealTimeState realTimeState =
          R1RealTimeState.fromFastMsgRsp(rspMsg.extra!);

      if (reserve) return realTimeState.pcMode != targetMode;
      return realTimeState.pcMode == targetMode;
    });
  }

  @override
  Future<R1AllRealTimeData> requestAllRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      R1RealTimeInfo realTimeInfo =
          R1RealTimeInfo.fromFastMsgRsp(property, fastInfoRspMsg.extra!);
      R1RealTimeState realTimeState =
          R1RealTimeState.fromFastMsgRsp(fastInfoRspMsg.extra!);

      return protocolWorker
          .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 1000)
          .then((slowInfoRspMsg) {
        if (slowInfoRspMsg.extra == null)
          throw ProtocolParseException('extra must not be null.');
        realTimeState.headlightState =
            ByteUtil.toUint4(ByteUtil.bytes2IntLe(slowInfoRspMsg.extra!, 80));

        return requestRealTimeError().then(
            (error) => R1AllRealTimeData(realTimeInfo, realTimeState, error));
      });
    });
  }

  @override
  Future<R1RealTimeError> requestRealTimeError() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestErrorCodeMsg(), timeoutMs: 1000)
        .then((errorCodeRspMsg) {
      return R1RealTimeError.fromErrorCodeMsgRsp(errorCodeRspMsg.data);
    });
  }

  @override
  Future<R1RealTimeInfo> requestRealTimeInfo() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return R1RealTimeInfo.fromFastMsgRsp(property, fastInfoRspMsg.extra!);
    });
  }

  @override
  Future<R1RealTimeState> requestRealTimeState() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestFastInfoMsg(), timeoutMs: 1000)
        .then((fastInfoRspMsg) {
      if (fastInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      return R1RealTimeState.fromFastMsgRsp(fastInfoRspMsg.extra!);
    });
  }

  @override
  Future<R1Settings> requestSettings() {
    return protocolWorker
        .sendAndGetRsp(EzcanFactory.genRequestSlowInfoMsg(), timeoutMs: 1000)
        .then((slowInfoRspMsg) {
      if (slowInfoRspMsg.extra == null)
        throw ProtocolParseException('extra must not be null.');
      R1Settings settings = R1Settings.fromSlowRspMsg(slowInfoRspMsg.extra!);

      var requestLanguageMsg = EzcanFactory.genLocalStandardReadMsg(
          EzcanConstant.ID_LANGUAGE,
          Uint8ClampedList.fromList([0, 0, 0, 0, 0, 0, 0, 0]),
          8);
      return protocolWorker
          .sendAndGetRsp(requestLanguageMsg, timeoutMs: 1000)
          .then((languageRspMsg) {
        settings.language =
            ByteUtil.toUint8(ByteUtil.bytes2UIntLe(languageRspMsg.data, 0, 4));

        var requestVolumeMsg = EzcanFactory.genLocalStandardReadMsg(
            EzcanConstant.ID_VOLUME,
            Uint8ClampedList.fromList([0, 0, 0, 0, 0, 0, 0, 0]),
            8);
        return protocolWorker
            .sendAndGetRsp(requestVolumeMsg, timeoutMs: 1000)
            .then((volumeRspMsg) {
          settings.volume = ByteUtil.toUint8(
              ByteUtil.bytes2UIntLe(volumeRspMsg.data, 0, 4) ~/ 100);
          return settings;
        });
      });
    });
  }
}

class StatisticsMocker {
  /// 单位：秒
  int rideTimeCountStartAt = -1;
  int totalMileageCountStartAt = -1;

  int lastMaxSpeed = 0;
  int lastMaxPower = 0;
  int lastMaxTemp = 0;

  void reset() {
    rideTimeCountStartAt = -1;
    totalMileageCountStartAt = -1;

    lastMaxSpeed = 0;
    lastMaxPower = 0;
    lastMaxTemp = 0;
  }
}
